<!DOCTYPE html>
<html lang="zh-cn">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>节拍器</title>

    <script>
        document.addEventListener("DOMContentLoaded", function () {
            let speed = 60, //节拍速度
                time = 0,   //play 过程 timeout 变量
                isPlay = false, //是否正在播放
                rangeValue = document.getElementById("rangeValue"), //滑块元素
                showSpeed = function (){//显示速度值的方法（或者叫 update 方法）
                    rangeValue.value = speed;
                }; 
            /** 播放按钮点击 */
            document.getElementById("btnPlay").addEventListener("click", function () {
                isPlay = true;
                play();
                this.style.display = "none";
                document.getElementById("btnStop").style.display = "inline-block";
            });
            /** 停止按钮点击 */
            document.getElementById("btnStop").addEventListener("click", function () {
                window.clearTimeout(time);
                isPlay = false;
                this.style.display = "none";
                document.getElementById("btnPlay").style.display = "inline-block";
            });
            /** 减号按钮点击 */
            document.getElementById("btnSub").addEventListener("click", function () {
                speed--;
                showSpeed();
            });
            /** 加号按钮点击 */
            document.getElementById("btnAdd").addEventListener("click", function () {
                speed++;
                showSpeed();
            });
            /** 滑动条更改 */
            rangeValue.addEventListener("change", function () {
                speed = this.value * 1;
                showSpeed();
            });
            /** 播放 */
            let play = function (){
                window.clearTimeout(time);
                playsound();
                if (isPlay) {
                    time = window.setTimeout(play, Math.floor(60000 / speed));
                };
            }
            let audioCtx = new AudioContext();
            /** 发声 */
            let playsound = function (){
                let oscillator = audioCtx.createOscillator();
                let gainNode = audioCtx.createGain();
                oscillator.connect(gainNode);
                gainNode.connect(audioCtx.destination);
                oscillator.type = 'sine';
                oscillator.frequency.setValueAtTime(220, audioCtx.currentTime);
                oscillator.frequency.linearRampToValueAtTime(50, audioCtx.currentTime + 0.1);
                gainNode.gain.setValueAtTime(0, audioCtx.currentTime);
                gainNode.gain.linearRampToValueAtTime(1, audioCtx.currentTime + 0.01);
                gainNode.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.5);
                oscillator.start(audioCtx.currentTime);
                oscillator.stop(audioCtx.currentTime + 0.5);
            }
        });
    </script>
</head>

<body>
    <section>
        <div id="msg"></div>
        <section>
            <div>
                <button id="btnSub">➖</button>
                <div><input type="number" style="width:95%;" id="rangeValue" value="60"></div>
                <button id="btnAdd">➕</button>
            </div>
        </section>
        <button id="btnPlay">▶️</button>
        <button id="btnStop" style="display: none">⏹️</button>
    </section>
</body>

</html>